﻿using System.Data;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Devonline.Core;
using Devonline.Http;
using Devonline.Identity.Admin.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.OData.Query;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;

namespace Devonline.Identity.Admin.Controllers
{
    /// <summary>
    /// 角色
    /// </summary>    
    [Route("api/[controller]")]
    [SecurityHeaders]
    [ApiController]
    [Authorize(Roles = AppSettings.GROUP_MAINTAINERS)]
    public class RolesController : ControllerBase
    {
        private readonly IdentityDbContext _context;
        private readonly RoleManager<Role> _roleManager;
        private readonly ILogger<RolesController> _logger;

        public RolesController(
            IdentityDbContext context,
            RoleManager<Role> roleManager,
            ILogger<RolesController> logger)
        {
            _context = context;
            _roleManager = roleManager;
            _logger = logger;
        }

        [HttpGet]
        [EnableQuery]
        public IActionResult Get()
        {
            _logger.LogInformation("user {user} query the role list", User.Identity.Name);
            return Ok(_context.Roles);
        }
        /// <summary>
        /// 添加角色
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPost]
        public async Task<IActionResult> CreateAsync(IdentityViewModel viewModel)
        {
            _logger.LogInformation("user {user} will add the role {role}", User.Identity.Name, viewModel.Name);
            if (await _roleManager.RoleExistsAsync(viewModel.Name))
            {
                return BadRequest($"角色 {viewModel.Name} 已经存在!");
            }

            var role = new Role
            {
                Name = viewModel.Name,
                Alias = viewModel.Alias,
                Image = viewModel.Image,
                Type = viewModel.Type,
                Description = viewModel.Description
            };

            role.Create(User.Identity.Name);
            role.Update(User.Identity.Name);

            //处理新增附件
            await _context.AddAttachmentsAsync(role, viewModel.Attachments);
            var result = await _roleManager.CreateAsync(role);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to add the role {role}", User.Identity.Name, role.Name);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to add the role {role}, error message is: {errorMessage}", User.Identity.Name, role.Name, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 修改
        /// </summary>
        /// <param name="viewModel"></param>
        /// <returns></returns>
        [HttpPut("{id}")]
        public async Task<IActionResult> ChangeAsync(string id, IdentityViewModel viewModel)
        {
            _logger.LogInformation("user {user} will change the role {role}", User.Identity.Name, id);
            var role = await _roleManager.FindByIdAsync(id);
            if (role == null)
            {
                return NotFound();
            }

            viewModel.CopyTo(role);

            //处理附件, 无附件则不用写下面的代码及删除文件的代码
            var files = await _context.UpdateAttachmentsAsync(role, viewModel.Attachments);
            if (files.IsNotNullOrEmpty() && files.Any(x => x == role.Image))
            {
                role.Image = null;
            }

            role.Update(User.Identity.Name);
            var result = await _roleManager.UpdateAsync(role);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to change the role {role}", User.Identity.Name, role.Name);
                files.Delete(_logger);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to change the role {role}, error message is: {errorMessage}", User.Identity.Name, role.Name, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 添加角色的一个 Claim
        /// </summary>
        /// <param name="id"></param>
        /// <param name="claim"></param>
        /// <returns></returns>
        [HttpPut("AddClaim/{id}")]
        public async Task<ActionResult> AddClaimAsync(string id, Claim claim)
        {
            _logger.LogInformation("user {user} will add claim to role {role}", User.Identity.Name, id);
            var role = await _roleManager.FindByIdAsync(id);
            if (role == null)
            {
                return BadRequest($"角色 {id} 不存在!");
            }

            var result = await _roleManager.AddClaimAsync(role, claim);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to add claim to role {role}", User.Identity.Name, role.Name);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to add claim to role {role}, error message is: {errorMessage}", User.Identity.Name, role.Name, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 移除角色的一个 Claim
        /// </summary>
        /// <param name="id"></param>
        /// <param name="claim"></param>
        /// <returns></returns>
        [HttpPut("RemoveClaim/{id}")]
        public async Task<ActionResult> RemoveClaimAsync(string id, Claim claim)
        {
            _logger.LogInformation("user {user} will remove claim to role {role}", User.Identity.Name, id);
            var role = await _roleManager.FindByNameAsync(id);
            if (role == null)
            {
                return BadRequest($"角色 {id} 不存在!");
            }

            var result = await _roleManager.RemoveClaimAsync(role, claim);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to remove claim to role {role}", User.Identity.Name, role.Name);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to remove claim to role {role}, error message is: {errorMessage}", User.Identity.Name, role.Name, errorMessage);
            }

            return BadRequest(errorMessage);
        }
        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteAsync(string id)
        {
            _logger.LogInformation("user {user} will delete the role {role}", User.Identity.Name, id);
            var role = await _roleManager.FindByNameAsync(id);
            if (role == null)
            {
                return NotFound();
            }

            //处理附件, 无附件则不用写下面的代码及删除文件的代码
            var files = await _context.DeleteAttachmentsAsync(id);

            var result = await _roleManager.DeleteAsync(role);
            if (result.Succeeded)
            {
                _logger.LogWarning("user {user} success to delete the role {role}", User.Identity.Name, role.Name);
                files.Delete(_logger);
                return Ok();
            }

            var errorMessage = string.Empty;
            if (result.Errors.IsNotNullOrEmpty())
            {
                errorMessage = result.Errors.Select(x => $"{x.Code}: {x.Description}").ToString<string>();
                _logger.LogWarning("user {user} fail to delete the role {role}, error message is: {errorMessage}", User.Identity.Name, role.Name, errorMessage);
            }

            return BadRequest(errorMessage);
        }
    }
}
